///////////////////
/// mkII - Core ///
///////////////////

#pragma once

namespace mk
{
namespace Core
{
namespace Math
{

MK_FORCEINLINE Vector1ConstValue Add
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_add_ss( a.r, b.r ));
}

MK_FORCEINLINE Vector1ConstValue Sub
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_sub_ss( a.r, b.r ));
}

MK_FORCEINLINE Vector1ConstValue Mul
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_mul_ss( a.r, b.r ));
}

MK_FORCEINLINE Vector1ConstValue Div
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_div_ss( a.r, b.r ));
}

MK_FORCEINLINE Vector1ConstValue MAdd
(
    Vector1ConstValue a,
    Vector1ConstValue b,
    Vector1ConstValue c
)
{
    return Vector1(_mm_add_ss( _mm_mul_ss( a.r, b.r ), c.r ));
}

MK_FORCEINLINE Vector1ConstValue Sqrt
( 
    Vector1ConstValue v
)
{
    return Vector1(_mm_sqrt_ss( v.r ));
}

MK_FORCEINLINE Vector1ConstValue Reciprocal
(
    Vector1ConstValue v
)
{
    return Vector1(_mm_div_ss( Constants::real4_one, v.r ));
}

MK_FORCEINLINE Vector1ConstValue FastReciprocal
(
    Vector1ConstValue v
)
{
    return Vector1(_mm_rcp_ss( v.r ));
}


MK_FORCEINLINE Vector1ConstValue FastReciprocalSqrt
(
    Vector1ConstValue v
)
{
    return Vector1(_mm_rsqrt_ss( v.r ));
}

MK_FORCEINLINE Vector1ConstValue Mod
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(ModVector1(a.r, b.r));
}

MK_FORCEINLINE Vector1ConstValue Min
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_min_ss( a.r, b.r ));
}

MK_FORCEINLINE Vector1ConstValue Max
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_max_ss( a.r, b.r ));
}

MK_FORCEINLINE Vector1ConstValue Floor
(
    Vector1ConstValue v
)
{
    return Vector1(FloorVector1(v.r));
}

MK_FORCEINLINE Vector1ConstValue Ceil
(
    Vector1ConstValue v
)
{
    return Vector1(CeilVector1(v.r));
}

MK_FORCEINLINE Vector1ConstValue Round
(
    Vector1ConstValue v
)
{
    return Vector1(RoundVector1(v.r));
}

MK_FORCEINLINE Vector1ConstValue Or
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_or_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector1ConstValue And
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_and_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector1ConstValue XOr
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_xor_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector1ConstValue Not
(
    Vector1ConstValue a
)
{
    return AndNot( Vector1(Constants::uint_true_mask), a );
}

MK_FORCEINLINE Vector1ConstValue AndNot
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_andnot_ps( b.r, a.r ));
}

MK_FORCEINLINE Vector1ConstValue Select
(
    Vector1ConstValue m,
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    Vector128r m1 = _mm_and_ps(a.r, m.r);
    Vector128r m2 = _mm_andnot_ps(m.r, b.r);
    return Vector1(_mm_or_ps(m1, m2));
}

MK_FORCEINLINE Vector1ConstValue IsEqualMask
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_cmpeq_ss(a.r, b.r));
}

MK_FORCEINLINE Vector1ConstValue IsLessMask
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_cmplt_ss(a.r, b.r));
}

MK_FORCEINLINE Vector1ConstValue IsLessEqMask
(
    Vector1ConstValue a,
    Vector1ConstValue b
)
{
    return Vector1(_mm_cmple_ss(a.r, b.r));
}

MK_FORCEINLINE bool IsTrue
(
    Vector1ConstValue mask
)
{
    return ( _mm_movemask_ps(mask.r) & 1 ) == 1;
}

MK_FORCEINLINE bool IsFalse
(
    Vector1ConstValue mask
)
{
    return ( _mm_movemask_ps(mask.r) & 1 ) == 0;
}

MK_FORCEINLINE Vector1ConstValue LoadVector1
(
    real32 const* src
)
{
    Vector1 r;
    r.r = _mm_load_ss( src );
    return r;
}

MK_FORCEINLINE real32* StoreVector1
(
    real32*             dst,
    Vector1ConstValue   v
)
{
    _mm_store_ss( dst, v.r );
    return dst;
}


} // namespace Math
} // namespace Core
} // namespace mk

